package com.batsoft.trade.api.core.shiro;

import com.batsoft.trade.api.core.shiro.util.PwdUtil;
import com.gomyb.redis.RedisService;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.web.filter.DelegatingFilterProxy;

import javax.servlet.Filter;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @author <a href="mailto:HelloHeSir@gmail.com">Mr_He</a>
 * @Copyright (c)</   b> HeC<br/>
 * @createTime 2018/10/30 10:29
 * @Description:
 */
@Configuration
@EnableConfigurationProperties(ShiroProperties.class)
public class ShiroConfig {

    @Autowired
    private ShiroProperties properties;

    @Bean
    public FilterRegistrationBean<DelegatingFilterProxy> delegatingFilterProxy() {
        FilterRegistrationBean<DelegatingFilterProxy> filterRegistrationBean = new FilterRegistrationBean<>();
        DelegatingFilterProxy proxy = new DelegatingFilterProxy();
        proxy.setTargetFilterLifecycle(true);
        proxy.setTargetBeanName("shiroFilter");
        filterRegistrationBean.setFilter(proxy);
        return filterRegistrationBean;
    }

    @Bean("shiroFilter")
    public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        //配置过滤链
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>(properties.getFilterUrl().size());
        for (Map.Entry<String, String> map : properties.getFilterUrl().entrySet()) {
            filterChainDefinitionMap.put(map.getKey(), map.getValue());
        }
        // 如果不设置默认会自动寻找Web工程根目录下的"/login.html"页面
        shiroFilterFactoryBean.setLoginUrl(properties.getLoginUrl());
        // 登录成功后要跳转的链接
        shiroFilterFactoryBean.setSuccessUrl(properties.getSuccessUrl());
        // 自定义过滤器，会覆盖默认过滤器
        Map<String, Filter> filters = new HashMap<>(2);
        //登录过滤器
        MyLogoutFilter logoutFilter = new MyLogoutFilter();
        filters.put("logout", logoutFilter);
        MyAuthFilter authFilter = new MyAuthFilter();
        //权限验证过滤器
        filters.put("authc", authFilter);
        shiroFilterFactoryBean.setFilters(filters);
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactoryBean;
    }

    /**
     * 自定义Realm创建
     */
    @Bean
    public MyShiroRealm myShiroRealm(CredentialsMatcher credentialsMatcher) {
        MyShiroRealm myShiroRealm = new MyShiroRealm();
        myShiroRealm.setCredentialsMatcher(credentialsMatcher);
        return myShiroRealm;
    }

    /**
     * 交由SecurityManage管理
     */
    @Bean
    @DependsOn({"credentialsMatcher"})
    public SecurityManager securityManager(CredentialsMatcher credentialsMatcher, CacheManager cacheManager, SessionManager sessionManager) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(myShiroRealm(credentialsMatcher));
        securityManager.setCacheManager(cacheManager);
        securityManager.setSessionManager(sessionManager);
        return securityManager;
    }

    /**
     * 功能增强
     */
    @Bean(name = "credentialsMatcher")
    public CredentialsMatcher credentialsMatcher(RedisService redisService) {
        RetryLimitHashedCredentialsMatcher credentialsMatcher = new RetryLimitHashedCredentialsMatcher(redisService);
        //加密方式
        credentialsMatcher.setHashAlgorithmName(PwdUtil.ALGORITHM_NAME);
        //加密迭代次数
        credentialsMatcher.setHashIterations(PwdUtil.ITERATION_COUNT);
        //true加密用的hex编码，false用的base64编码
        credentialsMatcher.setStoredCredentialsHexEncoded(PwdUtil.HEX_ENCODED);
        //重新尝试的次数（自己定义的）
        credentialsMatcher.setRetryMax(properties.getRetryMax());
        return credentialsMatcher;
    }

    /**
     * (基于redis的)用户授权信息Cache
     */
    @Bean
    public CacheManager redisCacheManager(RedisService redisService) {
        return new RedisCacheManage(redisService);
    }

}
